using System.Collections.Generic;
using UnityEngine;

namespace HyuFrameWork
{
    public class PoolData
    {
        public Transform poolRoot;
        public GameObject prefab;
        public Queue<GameObject> poolObjs = new Queue<GameObject>();
        public int limit = 5;
        public int count = 0;
    }
    
    //不做显示与隐藏 不做初始化与析构 只获得实例后的物品（处理逻辑在外部执行）
    public class PoolService : ServiceBase
    {
        public Dictionary<string,PoolData> pools = new Dictionary<string,PoolData>();
        
        public void Register(GameObject prefab, int limit=5)
        {
            if(pools.ContainsKey(prefab.name)) return;
            var root = new GameObject(prefab.name + "Root").transform;
            root.SetParent(transform);
            pools.Add(prefab.name,new PoolData
            {
                poolRoot = root,
                prefab = prefab,
                limit = limit
            });
        }
        
        public void Register(PoolData poolData)
        {
            if(pools.ContainsKey(poolData.prefab.name)) return;
            pools.Add(poolData.prefab.name,poolData);
        }

        public void Unregister(GameObject prefab)
        {
            if (!pools.TryGetValue(prefab.name,out var item)) return;

            while (item.poolObjs.Count > 0)
            {
                var obj = item.poolObjs.Dequeue();
                if(obj) SafeDestroy(obj);
            }
            pools.Remove(prefab.name);
        }

        public void UnregisterAll()
        {
            foreach (var data in pools.Values)
            {
                Unregister(data.prefab);
            }

            pools.Clear();
        }

        public bool IsRegisted(GameObject prefab)
        {
            return pools.ContainsKey(prefab.name);
        }

        public GameObject Spawn(GameObject obj)
        {
            Register(obj);
            
            var poolData = pools[obj.name];
            return SpawnByData(poolData);
        }
        
        public GameObject Spawn(string name)
        {
            if (pools.TryGetValue(name, out var poolData))
            {
                return SpawnByData(poolData);
            }
            else
            {
                Debug.LogError("When you Spawn(string name) No Register!");
                return null;
            }
        }
        
        private GameObject SpawnByData(PoolData poolData)
        {
            GameObject result = default;
            if (poolData.poolObjs.Count > 0)
            {
                result = poolData.poolObjs.Dequeue();
            }
            
            if (!result)
            {
                result = Instantiate(poolData.prefab, poolData.poolRoot);
                ++poolData.count;
                result.name = $"{poolData.prefab.name}_{poolData.count}";
            }
            
            return result;
        }


        public void DeSpawn(GameObject obj,string name) 
        {
            if (!pools.TryGetValue(name,out var poolData))
            {
                SafeDestroy(obj.gameObject);
                return;
            }

            if (poolData.poolObjs.Count >= poolData.limit)
            {
                SafeDestroy(obj.gameObject);
                --poolData.count;
                return;
            }

            if(obj)
                obj.transform.SetParent(poolData.poolRoot, true);
            poolData.poolObjs.Enqueue(obj);
        }

        private static void SafeDestroy(GameObject go)
        {
#if UNITY_EDITOR
            if (Application.isPlaying)
            {
                Destroy(go);    
            }
            else
            {
                DestroyImmediate(go);
            }
#else
            Destroy(go);
#endif
        }
    }
}
